package sim;
import java.io.File;
import java.io.FileNotFoundException;


/**
 * 
 */

/**
 * @author Piotr
 *
 */
public class MEMStage extends PipeStage {
	
	private DataMemory dm;

	/**
	 * Creates a new MEMStage without initializing the Data Memory.
	 */
	MEMStage() {
		super();
		dm = new DataMemory();
	}
	
	MEMStage(File dataFile) {
		super();
		try {
			dm = new DataMemory(dataFile);
		} catch (FileNotFoundException e) {
			System.out.println("Error reading " + dataFile 
					+ ". Did not initialize memory.");
			dm = new DataMemory();
		}
	}

	
	
	@Override
	int cycle() throws InvalidInstructionException {
		instr = Simulator.exs.passInstruction();
		if (instr == null) {
			return 0;
		} else {
			if (instr.isNop()) {
				return 0;
			} else {
				instr.cycle();
				switch (instr.iType) {
				case LOAD:
					doLoad(instr);
					break;
				case STORE:
					doStore(instr);
					break;
				default:
					break;
				}
			}
		}
		return 1;
	}
	
	private void doStore(Instruction instr) {
		if (!instr.arg1Ready) {
			// Forward value
			Integer val = Simulator.hzc.tryForwarding(instr.arg1Reg, this.getClass());
			if (val == null) {
				System.out.println("Stall needed in MEM stage. Should not happen.");
				System.exit(1);
			} else {
				instr.arg1Val = val;
				instr.arg1Ready = true;
			}
		}
		dm.write(instr.memAddr, instr.arg1Val); //memAddr is calculated in EX		
	}

	private void doLoad(Instruction instr) {
		instr.setDest1Val(dm.read(instr.memAddr)); //memAddr is calculated in EX
	}
	
	/**
	 * Returns a memory dump as a string.
	 * @return
	 */
	String dumpMemory() {
		return dm.toString();
	}

}
